using MapsterMapper;
using AiQiuQuan.Sport.Model.Models;
using AiQiuQuan.Sport.Core;
using EasyCaching.Core;
using AiQiuQuan.Sport.WebApi.Entities;
using AiQiuQuan.Sport.WebApi.Repositories;
using Microsoft.EntityFrameworkCore;
using AiQiuQuan.Sport.Model.Enums;
using AiQiuQuan.Sport.Core.Tool;
using AiQiuQuan.Sport.WebApi.Core;

namespace AiQiuQuan.Sport.WebApi.Services.Impl
{
    /// <summary>
    /// 课程管理
    /// </summary>
    public class CourseService : ICourseService
    {
        private readonly IMapper _mapper;
        private readonly ICurrentInfo _currentInfo;
        private readonly IRedisCachingProvider _cache;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly ICourseRepository _courseRepository;
        private readonly ICourseDetailRepository _courseDetailRepository;
        private readonly ICourseCoacherRepository _courseCoacherRepository;
        private readonly ICoursePlanRepository _coursePlanRepository;
        private readonly IVenueInfoRepository _venueInfoRepository;
        private readonly IBaseUserRepository _baseUserRepository;
        private readonly ICourseStudentRepository _courseStudentRepository;
        private readonly ICoacherRepository _coacherRepository;
        private readonly IBaseUserExtendInfoRepository _baseUserExtendInfoRepository;
        private readonly IBaseUserTennisLevelConfigRepository _baseUserTennisLevelConfigRepository;
        private readonly ICourseOrderRepository _courseOrderRepository;
        private readonly ICourseStuentRecordRepository _courseStuentRecordRepository;
        private readonly ICourseStudentService _courseStudentService;
        private readonly ICoacherVenueRepository _coacherVenueRepository;
        private readonly ICoacherStarRepository _coacherStarRepository;
        private readonly ICoacherBookRepository _coacherBookRepository;

        /// <summary>
        /// ctor
        /// </summary>
        public CourseService(
            IMapper mapper,
            ICurrentInfo currentInfo,
            IRedisCachingProvider cache,
            IUnitOfWorkManager unitOfWorkManager,
            ICourseRepository courseRepository,
            IVenueInfoRepository venueInfoRepository,
            ICoursePlanRepository coursePlanRepository,
            ICourseDetailRepository courseDetailRepository,
            ICourseCoacherRepository courseCoacherRepository,
            IBaseUserRepository baseUserRepository,
            ICourseStudentRepository courseStudentRepository,
            ICoacherRepository coacherRepository,
            IBaseUserExtendInfoRepository baseUserExtendInfoRepository,
            IBaseUserTennisLevelConfigRepository baseUserTennisLevelConfigRepository,
            ICourseOrderRepository courseOrderRepository,
            ICourseStuentRecordRepository courseStuentRecordRepository,
            ICourseStudentService courseStudentService,
            ICoacherVenueRepository coacherVenueRepository,
            ICoacherStarRepository coacherStarRepository,
            ICoacherBookRepository coacherBookRepository)
        {
            _mapper = mapper;
            _cache = cache;
            _currentInfo = currentInfo;
            _unitOfWorkManager = unitOfWorkManager;
            _courseRepository = courseRepository;
            _venueInfoRepository = venueInfoRepository;
            _coursePlanRepository = coursePlanRepository;
            _courseDetailRepository = courseDetailRepository;
            _courseCoacherRepository = courseCoacherRepository;
            _baseUserRepository = baseUserRepository;
            _courseStudentRepository = courseStudentRepository;
            _coacherRepository = coacherRepository;
            _baseUserExtendInfoRepository = baseUserExtendInfoRepository;
            _baseUserTennisLevelConfigRepository = baseUserTennisLevelConfigRepository;
            _courseOrderRepository = courseOrderRepository;
            _courseStuentRecordRepository = courseStuentRecordRepository;
            _courseStudentService = courseStudentService;
            _coacherVenueRepository = coacherVenueRepository;
            _coacherStarRepository = coacherStarRepository;
            _coacherBookRepository = coacherBookRepository;
        }

        /// <summary>
        /// 查询一条记录
        /// </summary>
        public async Task<CourseDto> GetAsync(Guid id)
        {
            var course = await _courseRepository.FirstOrDefaultAsync(m => m.ID == id);
            var result = _mapper.Map<Course, CourseDto>(course);
            if (result != null)
            {
                result.DetailList = await GetCourseDetailListAsync(result.ID);
                result.CoacherList = await GetCourseCoacherListAsync(result.ID);
                result.PlanList = await GetCoursePlanListAsync(result.ID);
            }

            return result;
        }

        /// <summary>
        /// 查询课程及附加信息
        /// </summary>
        public async Task<CourseDto> QueryCouseAndAttachInfoAsync(CourseInfoRequestDto request)
        {
            var course = await _courseRepository.FirstOrDefaultAsync(m => m.ID == request.ID);
            var result = _mapper.Map<Course, CourseDto>(course);
            result.IsCourseManage = await _courseCoacherRepository.AnyAsync(m => m.CourseId == request.ID && m.CoacherUserId == _currentInfo.UserId && m.IsCourseManage);
            if (result != null)
            {
                result.Distance = DistanceTool.GetDistanceKM(result.Lat, result.Lng, request.Lat, request.Lng);
                result.DetailList = await GetCourseDetailListAsync(result.ID);
                result.CoacherList = await GetCourseCoacherListAsync(result.ID);
                result.StudentList = await GetCourseStudentListAsync(result.ID);
                result.PlanList = new List<CoursePlanDto>();
                var planList = await GetCoursePlanListAsync(result.ID);
                if (planList.Any())
                {
                    for (var i = DateTime.Now.Date; i <= DateTime.Now.Date.AddDays(6); i = i.AddDays(1))
                    {
                        var plan = planList.FirstOrDefault(m => m.WeekDay == i.DayOfWeek);
                        if (plan != null)
                        {
                            plan.Date = new DateTimeOffset(i);
                            var key = $"course:{result.ID:N}:{plan.Date.Value:yyyyMMdd}";
                            var isenable = await _cache.StringGetAsync(key);
                            plan.IsEnable = string.IsNullOrWhiteSpace(isenable) || isenable == "1";
                            result.PlanList.Add(plan);
                        }
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 查询课程信息
        /// </summary>
        public async Task<CourseDto> QueryCouseAsync(CourseInfoRequestDto request)
        {
            var course = await _courseRepository.FirstOrDefaultAsync(m => m.ID == request.ID);
            var result = _mapper.Map<Course, CourseDto>(course);
            result.IsCourseManage = await _courseCoacherRepository.AnyAsync(m => m.CourseId == request.ID && m.CoacherUserId == _currentInfo.UserId && m.IsCourseManage);
            if (result != null)
            {
                result.Distance = DistanceTool.GetDistanceKM(result.Lat, result.Lng, request.Lat, request.Lng);
                result.DetailList = await GetCourseDetailListAsync(result.ID);
                result.PlanList = new List<CoursePlanDto>();
                var planList = await GetCoursePlanListAsync(result.ID);
                if (planList.Any())
                {
                    for (var i = DateTime.Now.Date; i <= DateTime.Now.Date.AddDays(6); i = i.AddDays(1))
                    {
                        var plan = planList.FirstOrDefault(m => m.WeekDay == i.DayOfWeek);
                        if (plan != null)
                        {
                            plan.Date = new DateTimeOffset(i);
                            var key = $"course:{result.ID:N}:{plan.Date.Value:yyyyMMdd}";
                            plan.IsEnable = await _cache.StringGetAsync(key) == "1";
                            planList.Add(plan);
                        }
                    }
                }
            }

            return result;
        }

        /// <summary>
        /// 获取课程教练列表
        /// </summary>
        /// <param name="courseId">课程ID</param>
        public async Task<List<CourseCoacherDto>> QueryCourseCoacherListAsync(Guid courseId)
        {
            var list = await GetCourseCoacherListAsync(courseId);
            return list;
        }

        /// <summary>
        /// 删除课程教练
        /// </summary>
        public async Task<UnaryResult> DeleteCourseCoacherAsync(CourseCoacherDelDto request)
        {
            await _courseCoacherRepository.DeleteAsync(m => m.CourseId == request.CourseId && m.CoacherUserId == request.CoacherUserId);
            var count = await _courseCoacherRepository.CountAsync(m => m.CourseId == request.CourseId);
            var builder = await _courseRepository.UpdatePartialAsync();
            await builder.Set(m => m.CoacherCount, count).Where(m => m.ID == request.CourseId).ExecuteAsync();
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 获取课程学生列表
        /// </summary>
        /// <param name="courseId">课程ID</param>
        public async Task<List<CourseStudentDto>> QueryCourseStudentListAsync(Guid courseId)
        {
            var list = await GetCourseStudentListAsync(courseId);
            return list;
        }

        /// <summary>
        /// 课程学生记录
        /// </summary>
        public async Task<PageResult<CourseStuentRecordDto>> QueryCourseStuentRecordListAsync(CourseStudentRecordPageRequestDto request)
        {
            if (request.UserId != _currentInfo.UserId || !await _courseCoacherRepository.AnyAsync(m => m.CourseId == request.CourseId && m.CoacherUserId == _currentInfo.UserId))
            {
                return PageResult.Empty<CourseStuentRecordDto>();
            }

            var pagelist = await _courseStuentRecordRepository.AsNoTracking()
                .Where(m => m.CourseId == request.CourseId && m.UserId == request.UserId)
                .OrderByDescending(m => m.CreateTime).PageListAsync<CourseStuentRecord, CourseStuentRecordDto>(request, _mapper);
            return pagelist;
        }

        /// <summary>
        /// 课程分页列表
        /// </summary>
        public async Task<PageResult<CourseDto>> PageListAsync(CoursePageRequestDto request)
        {
            var queryable = _courseRepository.AsNoTracking();
            if (request.CourseType.HasValue)
            {
                queryable = queryable.Where(m => m.CourseType == request.CourseType.Value);
            }

            if (request.IsPlatform)
            {
                if (request.State.HasValue)
                {
                    queryable = queryable.Where(m => m.State == request.State);
                }
            }
            else
            {
                queryable = queryable.Where(m => m.State == CourseStateEnum.Processing);
            }

            if (request.VenueId.HasValue)
            {
                queryable = queryable.Where(m => m.VenueId == request.VenueId.Value);
            }

            if (request.ProvinceId.HasValue && request.CityId.HasValue)
            {
                queryable = queryable.Where(m => m.ProvinceId == request.ProvinceId && m.CityId == request.CityId);
            }
            else if (request.ProvinceId.HasValue && !request.CityId.HasValue)
            {
                queryable = queryable.Where(m => m.ProvinceId == request.ProvinceId);
            }

            var list = await queryable.OrderByDescending(m => m.CreateTime).PageListAsync<Course, CourseDto>(request, _mapper);
            await SetCouseAttachData(list.Result, request);

            return list;
        }

        /// <summary>
        /// 获取课程购买信息
        /// </summary>
        /// <param name="courseDetailId">课程明细ID</param>
        public async Task<CouseBuyInfoDto> GetCourseBuyInfoAsync(Guid courseDetailId)
        {
            var queryable = from detail in _courseDetailRepository.AsNoTracking()
                            join course in _courseRepository.AsNoTracking()
                            on detail.CourseId equals course.ID
                            where detail.ID == courseDetailId
                            select new CouseBuyInfoDto
                            {
                                CourseId = course.ID,
                                CourseHeadUrl = course.HeadUrl,
                                CourseName = course.Name,
                                CourseType = course.CourseType,
                                CourseDetailId = detail.ID,
                                TimesCount = detail.TimesCount,
                                ValidMonth = detail.ValidMonth,
                                StartTime = detail.StartTime,
                                EndTime = detail.EndTime,
                                Price = detail.Price,
                            };
            return await queryable.FirstOrDefaultAsync();
        }

        /// <summary>
        /// 课程购买
        /// </summary>
        public async Task<UnaryResult<CourseBuyResultDto>> BuyAsync(CourseBuyRequestDto request)
        {
            var result = new CourseBuyResultDto();
            var detail = await _courseDetailRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == request.CourseDetailId);
            if (detail == null)
            {
                return UnaryResult.From(10, result, "课程信息已修改");
            }

            var course = await _courseRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == detail.CourseId);
            var unaryResult = await BuyValidAsync(course, request, result);
            if (unaryResult.Code != 0)
            {
                return unaryResult;
            }

            var order = await CreateOrderAsync(course, detail, request, result);
            await _courseOrderRepository.AddAsync(order);
            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 我的课程列表
        /// </summary>
        public async Task<PageResult<CourseDto>> GetMyCourseListAsync(CourseSelfPageRequestDto request)
        {
            var queryable = from course in _courseRepository.AsNoTracking()
                            join student in _courseStudentRepository.AsNoTracking()
                            on course.ID equals student.CourseId
                            where student.UserId == _currentInfo.UserId
                            select course;
            if (!string.IsNullOrWhiteSpace(request.Name))
            {
                queryable = queryable.Where(m => m.Name.Contains(request.Name));
            }

            var pageResult = await queryable.OrderBy(m => m.State).ThenByDescending(m => m.CreateTime)
                .PageListAsync<Course, CourseDto>(request, _mapper);
            foreach (var item in pageResult.Result)
            {
                if (request.Lat.HasValue)
                {
                    item.Distance = DistanceTool.GetDistanceKM(request.Lat.GetValueOrDefault(), request.Lng.GetValueOrDefault(), item.Lat, item.Lng);
                }

                var planList = await GetCoursePlanListAsync(item.ID);
                if (planList.Any())
                {
                    for (var i = DateTime.Now.Date; i <= DateTime.Now.Date.AddDays(6); i = i.AddDays(1))
                    {
                        var plan = planList.FirstOrDefault(m => m.WeekDay == i.DayOfWeek);
                        if (plan != null)
                        {
                            plan.Date = new DateTimeOffset(i);
                            var key = $"course:{item.ID:N}:{plan.Date.Value:yyyyMMdd}";
                            plan.IsEnable = await _cache.StringGetAsync(key) != "0";
                            planList.Add(plan);
                        }
                    }
                }

                item.PlanList = planList;
            }

            return pageResult;
        }

        /// <summary>
        /// 获取教练课程列表
        /// </summary>
        /// <param name="coacherUserId">教练用户ID</param>
        public async Task<List<CourseDto>> GetCoacherCourseListAsync(Guid coacherUserId)
        {
            var queryable = from courseCoacher in _courseCoacherRepository.AsNoTracking()
                            join course in _courseRepository.AsNoTracking()
                            on courseCoacher.CourseId equals course.ID
                            where courseCoacher.CoacherUserId == coacherUserId
                            select course;
            var list = await queryable.ToListAsync();
            return _mapper.Map<List<CourseDto>>(list);
        }

        /// <summary>
        /// 获取我的课程计划列表(团体课程、私教)
        /// </summary>
        public async Task<List<MyCoursePlanDto>> GetMyCoursePlanListAsync()
        {
            var list = new List<MyCoursePlanDto>();
            var currentTime = DateTime.Now;
            var courseStateList = new List<CourseStateEnum> { CourseStateEnum.Processing, CourseStateEnum.Stoped };
            var queryable = from courseStudent in _courseStudentRepository.AsNoTracking()
                            join course in _courseRepository.AsNoTracking()
                            on courseStudent.CourseId equals course.ID
                            where courseStudent.UserId == _currentInfo.UserId && courseStudent.IsEnable && courseStudent.EndTime > currentTime && courseStateList.Contains(course.State)
                            select course;
            var courseList = await queryable.ToListAsync();
            //团体课程计划处理
            foreach (var course in courseList)
            {
                var coursePlanList = await _coursePlanRepository.AsNoTracking().Where(m => m.CourseId == course.ID).ToListAsync();
                for (var i = currentTime.Date; i <= DateTime.Now.Date.AddDays(6); i = i.AddDays(1))
                {
                    var plan = coursePlanList.FirstOrDefault(m => m.WeekDay == i.DayOfWeek);
                    if (plan != null)
                    {
                        var key = $"course:{course.ID:N}:{i:yyyyMMdd}";
                        var isenable = await _cache.StringGetAsync(key);
                        var myPlan = new MyCoursePlanDto
                        {
                            CourseType = MyCourseTypeEnum.Course,
                            BusinessId = course.ID,
                            CourseDate = i,
                            StartTime = plan.StartTime,
                            EndTime = plan.EndTime,
                            CoursePlanIsEnable = string.IsNullOrWhiteSpace(isenable) || isenable == "1"
                        };
                        list.Add(myPlan);
                    }
                }
            }

            //私教处理
            var bookEndTime = currentTime.Date.AddDays(6);
            var bookStateList = new List<CoacherBookStateEnum> { CoacherBookStateEnum.Processing, CoacherBookStateEnum.Cancel };
            var bookList = await _coacherBookRepository.AsNoTracking()
                .Where(m => m.UserId == _currentInfo.UserId && m.BookDate >= currentTime.Date && m.BookDate <= bookEndTime.Date && bookStateList.Contains(m.State))
                .ToListAsync();
            foreach (var item in bookList)
            {
                var myPlan = new MyCoursePlanDto
                {
                    CourseType = MyCourseTypeEnum.Coacher,
                    BusinessId = item.BusinessId,
                    CourseDate = item.BookDate,
                    StartTime = item.StartTime,
                    EndTime = item.EndTime,
                    CoacherPlanState = item.State
                };
                list.Add(myPlan);
            }

            return list;
        }

        /// <summary>
        /// 教练课程列表
        /// </summary>
        public async Task<PageResult<CourseDto>> GetCoacherCourseListAsync(CourseSelfPageRequestDto request)
        {
            var queryable = from course in _courseRepository.AsNoTracking()
                            join coacher in _courseCoacherRepository.AsNoTracking()
                            on course.ID equals coacher.CourseId
                            where coacher.CoacherUserId == _currentInfo.UserId
                            select course;
            if (!string.IsNullOrWhiteSpace(request.Name))
            {
                queryable = queryable.Where(m => m.Name.Contains(request.Name));
            }

            var pageResult = await queryable.OrderBy(m => m.State).ThenByDescending(m => m.CreateTime)
                .PageListAsync<Course, CourseDto>(request, _mapper);
            if (request.Lat.HasValue)
            {
                foreach (var item in pageResult.Result)
                {
                    item.Distance = DistanceTool.GetDistanceKM(request.Lat.GetValueOrDefault(), request.Lng.GetValueOrDefault(), item.Lat, item.Lng);
                }
            }

            return pageResult;
        }

        /// <summary>
        /// 新增
        /// </summary>
        public async Task<UnaryResult> AddAsync(CourseAddDto model)
        {
            var course = _mapper.Map<Course>(model);
            course.ID = Guid.NewGuid();
            course.IsShow = true;
            course.IsRecommend = true;
            course.State = CourseStateEnum.Processing;
            course.VenueName = string.Empty;
            course.CoacherCount = model.CoacherList.Count;
            if (course.VenueId.HasValue)
            {
                var venue = await _venueInfoRepository.FirstOrDefaultAsync(m => m.ID == course.VenueId.Value);
                if (venue == null)
                {
                    return UnaryResult.Faild(10, "场馆不存在");
                }

                course.VenueName = venue.VI_Name;
                course.Address = venue.VI_Address;
                course.ProvinceId = venue.ProvinceID.Value;
                course.ProvinceName = venue.VI_P_Name;
                course.CityId = venue.CityID.Value;
                course.CityName = venue.VI_P_Name == venue.VI_C_Name ? "全部" : venue.VI_C_Name;
                course.Lng = venue.VI_Lng.Value;
                course.Lat = venue.VI_Lat.Value;
            }

            var detailList = _mapper.Map<List<CourseDetail>>(model.DetailList);
            detailList.ForEach(detail =>
            {
                detail.CourseId = course.ID;
                detail.CourseType = course.CourseType;
            });
            var coacherList = _mapper.Map<List<CourseCoacher>>(model.CoacherList);
            coacherList.ForEach(coacher =>
            {
                coacher.CourseId = course.ID;
                coacher.CourseType = course.CourseType;
            });
            var planList = _mapper.Map<List<CoursePlan>>(model.PlanList);
            if (planList != null && planList.Any())
            {
                planList.ForEach(plan =>
                {
                    plan.CourseId = course.ID;
                    plan.CourseType = course.CourseType;
                });
            }

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _courseRepository.AddAsync(course);
                await _courseCoacherRepository.BulkAddAsync(coacherList);
                await _courseDetailRepository.BulkAddAsync(detailList);
                if (planList != null && planList.Any())
                {
                    await _coursePlanRepository.BulkAddAsync(planList);
                }

                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 教练课程计划状态修改
        /// </summary>
        public async Task<UnaryResult> UpdateCoursePlanStateAsync(CoursePlanStateUpdateDto request)
        {
            if (!await _courseCoacherRepository.AnyAsync(m => m.CoacherUserId == _currentInfo.UserId && m.CourseId == request.CourseId))
            {
                return UnaryResult.Faild(10, "非课程管理教练");
            }

            var key = $"course:{request.CourseId:N}:{request.UpdateDate:yyyyMMdd}";
            var value = request.IsEnable ? "1" : "0";
            var expireTime = request.UpdateDate.Date.AddDays(1) - DateTimeOffset.Now;
            await _cache.StringSetAsync(key, value, expireTime);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 学生点名
        /// </summary>
        public async Task<UnaryResult> CallStudentAsync(CourseStudentRequestDto request)
        {
            if (!await _courseCoacherRepository.AnyAsync(m => m.CoacherUserId == _currentInfo.UserId && m.CourseId == request.CourseId))
            {
                return UnaryResult.Faild(10, "非课程教练");
            }

            var course = await _courseRepository.FirstOrDefaultAsync(m => m.ID == request.CourseId && m.CourseType == CourseTypeEnum.Times);
            if (course == null)
            {
                return UnaryResult.Faild(10, "非次数课程");
            }

            var dic = new Dictionary<Guid, decimal>();
            foreach (var item in request.CallStudentList)
            {
                var student = await _courseStudentRepository.AsNoTracking().FirstOrDefaultAsync(m => m.CourseId == request.CourseId && m.UserId == item.UserId);
                if (student == null || student.TimesCount < item.UseCount)
                {
                    return UnaryResult.Faild(10, "学生次数不足");
                }

                dic.Add(item.UserId, student.TimesCount - item.UseCount);
            }

            using (var uow = _unitOfWorkManager.Begin())
            {
                foreach (var item in request.CallStudentList)
                {
                    //增加课程学生、学生记录
                    var record = new CourseStuentRecordAddDto
                    {
                        CourseId = request.CourseId,
                        CourseType = CourseTypeEnum.Times,
                        ChangeCount = -(int)item.UseCount,
                        ValidMonth = 0,
                        StartTime = null,
                        EndTime = null,
                        UserId = item.UserId,
                        Remark = $"点名",
                        OpereateType = CourseRecordOperateTypeEnum.Call
                    };
                    await _courseStudentService.AddRecordAsync(record);
                    //假如次数为0时，更新对应次数课程订单为不可退款状态
                    if (dic[item.UserId] == 0)
                    {
                        var builder = await _courseOrderRepository.UpdatePartialAsync();
                        await builder.Set(m => m.IsNotRefund, true).Where(m => m.UserId == item.UserId && m.BusinessId == course.ID && !m.IsNotRefund).ExecuteAsync();
                    }
                }

                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 课程学生删除
        /// </summary>
        public async Task<UnaryResult> DeleteStudentAsync(CourseStudentDelDto request)
        {
            if (!request.IsPlatform && !await _courseCoacherRepository.AnyAsync(m => m.CourseId == request.CourseId && m.CoacherUserId == _currentInfo.UserId))
            {
                return UnaryResult.Faild(10, "非课程管理教练");
            }

            var builder = await _courseStudentRepository.UpdatePartialAsync();
            await builder.Set(m => m.IsEnable, false)
                .Set(m => m.TimesCount, 0)
                .Where(m => m.CourseId == request.CourseId && m.UserId == request.UserId)
                .ExecuteAsync();

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 课程相关状态、标记修改
        /// </summary>
        public async Task<UnaryResult> UpdateCourseFlagAsync(CourseFlagUpdateDto request)
        {
            if (!request.IsPlatform)
            {
                if (!request.CourseState.HasValue)
                {
                    return UnaryResult.Faild(10, "状态值必传");
                }

                if (!await _courseCoacherRepository.AnyAsync(m => m.CoacherUserId == _currentInfo.UserId && m.CourseId == request.CourseId && m.IsCourseManage))
                {
                    return UnaryResult.Faild(10, "非课程管理教练");
                }
            }

            var builder = await _courseRepository.UpdatePartialAsync();
            if (request.CourseState.HasValue)
            {
                builder = builder.Set(m => m.State, request.CourseState.Value);
            }

            if (request.IsShow.HasValue)
            {
                builder = builder.Set(m => m.IsShow, request.IsShow.Value);
            }

            if (request.IsRecommend.HasValue)
            {
                builder = builder.Set(m => m.IsRecommend, request.IsRecommend.Value);
            }

            await builder.Where(m => m.ID == request.CourseId).ExecuteAsync();
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 修改
        /// </summary>
        public async Task<UnaryResult> UpdateAsync(CourseUpdateDto model)
        {
            var course = await _courseRepository.FirstOrDefaultAsync(m => m.ID == model.ID);
            if (course == null)
            {
                return UnaryResult.Faild(10, "课程不存在");
            }

            if (course.CourseType != model.CourseType)
            {
                return UnaryResult.Faild(10, "课程类型不正确");
            }

            _mapper.Map(model, course);
            course.CoacherCount = model.CoacherList.Count;
            if (model.VenueId.HasValue)
            {
                var venue = await _venueInfoRepository.FirstOrDefaultAsync(m => m.ID == course.VenueId.Value);
                if (venue == null)
                {
                    return UnaryResult.Faild(10, "场馆不存在");
                }

                course.VenueName = venue.VI_Name;
                course.Address = venue.VI_Address;
                course.ProvinceId = venue.ProvinceID.Value;
                course.ProvinceName = venue.VI_P_Name;
                course.CityId = venue.CityID.Value;
                course.CityName = venue.VI_P_Name == venue.VI_C_Name ? "全部" : venue.VI_C_Name;
                course.Lng = venue.VI_Lng.Value;
                course.Lat = venue.VI_Lat.Value;
            }

            var detailList = _mapper.Map<List<CourseDetail>>(model.DetailList);
            detailList.ForEach(detail =>
            {
                detail.CourseId = course.ID;
                detail.CourseType = course.CourseType;
            });
            var coacherList = _mapper.Map<List<CourseCoacher>>(model.CoacherList);
            coacherList.ForEach(coacher =>
            {
                coacher.CourseId = course.ID;
                coacher.CourseType = course.CourseType;
            });
            var planList = _mapper.Map<List<CoursePlan>>(model.PlanList);
            if (planList != null && planList.Any())
            {
                planList.ForEach(plan =>
                {
                    plan.CourseId = course.ID;
                    plan.CourseType = course.CourseType;
                });
            }

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _courseCoacherRepository.DeleteAsync(m => m.CourseId == course.ID);
                await _courseDetailRepository.DeleteAsync(m => m.CourseId == course.ID);
                await _coursePlanRepository.DeleteAsync(m => m.CourseId == course.ID);
                await _courseRepository.UpdateAsync(course);
                await _courseCoacherRepository.BulkAddAsync(coacherList);
                await _courseDetailRepository.BulkAddAsync(detailList);
                if (planList != null && planList.Any())
                {
                    await _coursePlanRepository.BulkAddAsync(planList);
                }

                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 删除
        /// </summary>
        public async Task<UnaryResult> DeleteAsync(Guid id)
        {
            await _courseRepository.DeleteAsync(p => p.ID == id);
            await _courseCoacherRepository.DeleteAsync(m => m.CourseId == id);
            await _courseDetailRepository.DeleteAsync(m => m.CourseId == id);
            await _coursePlanRepository.DeleteAsync(m => m.CourseId == id);
            return UnaryResult.Succeed();
        }

        #region private methods
        /// <summary>
        /// 额外课程数据
        /// </summary>
        private async Task SetCouseAttachData(IList<CourseDto> courseList, CoursePageRequestDto request)
        {
            foreach (var item in courseList)
            {
                if (!request.IsPlatform)
                {
                    item.Distance = DistanceTool.GetDistanceKM(item.Lat, item.Lng, request.Lat.GetValueOrDefault(), request.Lng.GetValueOrDefault());
                    var courseCoacherList = await GetCourseCoacherSimpleListAsync(item.ID);
                    item.Coacher = courseCoacherList.FirstOrDefault(m => m.IsCourseManage);
                    item.Coacher ??= courseCoacherList.FirstOrDefault();
                }
                else
                {
                    item.StudentCount = await _courseStudentRepository.CountAsync(m => m.CourseId == item.ID && m.IsEnable);
                }
            }
        }

        /// <summary>
        /// 获取课程教练t概要列表
        /// </summary>
        private async Task<IList<CourseCoacherDto>> GetCourseCoacherSimpleListAsync(Guid courseId)
        {
            var queryable = from courseCoacher in _courseCoacherRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on courseCoacher.CoacherUserId equals user.ID
                            join coacher in _coacherRepository.AsNoTracking()
                            on courseCoacher.CoacherUserId equals coacher.UserId
                            where courseCoacher.CourseId == courseId
                            select new CourseCoacherDto
                            {
                                ID = courseCoacher.ID,
                                CourseId = courseCoacher.CourseId,
                                CourseType = courseCoacher.CourseType,
                                CreateTime = courseCoacher.CreateTime,
                                CoacherId = courseCoacher.CoacherId,
                                CoacherUserId = courseCoacher.CoacherUserId,
                                HeadUrl = user.U_Headportrait,
                                PicUrl = coacher.PicUrl,
                                Name = user.U_RealName ?? user.U_NickName,
                                NickName = user.U_NickName,
                                RealName = user.U_RealName,
                                Code = user.U_Code,
                                PhoneNo = user.U_PhoneNum,
                                IsCourseManage = courseCoacher.IsCourseManage,
                            };
            return await queryable.ToListAsync();
        }

        /// <summary>
        /// 获取课程教练列表
        /// </summary>
        private async Task<List<CourseCoacherDto>> GetCourseCoacherListAsync(Guid courseId)
        {
            var queryable = from courseCoacher in _courseCoacherRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on courseCoacher.CoacherUserId equals user.ID
                            join coacher in _coacherRepository.AsNoTracking()
                            on courseCoacher.CoacherId equals coacher.ID
                            join tennis1 in _baseUserExtendInfoRepository.AsNoTracking()
                            on user.ID equals tennis1.ID into tennis1d
                            from tennis1 in tennis1d.DefaultIfEmpty()
                            join tennis2 in _baseUserTennisLevelConfigRepository.AsNoTracking()
                            on tennis1.BaseUserTennisLevelConfigID equals tennis2.ID into tennis2d
                            from tennis2 in tennis2d.DefaultIfEmpty()
                            where courseCoacher.CourseId == courseId
                            select new CourseCoacherDto
                            {
                                ID = courseCoacher.ID,
                                CourseId = courseCoacher.CourseId,
                                CourseType = courseCoacher.CourseType,
                                CreateTime = courseCoacher.CreateTime,
                                CoacherId = courseCoacher.CoacherId,
                                CoacherUserId = courseCoacher.CoacherUserId,
                                HeadUrl = user.U_Headportrait,
                                Name = user.U_RealName ?? user.U_NickName,
                                RealName = user.U_RealName,
                                NickName = user.U_NickName,
                                Code = user.U_Code,
                                PhoneNo = user.U_PhoneNum,
                                IsCourseManage = courseCoacher.IsCourseManage,
                                IsCertificated = coacher.IsCertificated,
                                Introduction = coacher.Introduction,
                                PicUrl = coacher.PicUrl,
                                CoacherType = coacher.Type,
                                TennisLevel = tennis2.LevelName ?? "1.0",
                                Star = _coacherStarRepository.Where(m => m.CoacherUserId == courseCoacher.CoacherUserId).Average(m => m.Star)
                            };
            var result = await queryable.ToListAsync();
            foreach (var item in result)
            {
                item.VenueList = await _coacherVenueRepository.Where(m => m.CoacherUserId == item.CoacherUserId).Select(m => _mapper.Map<CoacherVenueDto>(m)).ToListAsync();
            }

            return result;
        }

        /// <summary>
        /// 获取课程学员列表
        /// </summary>
        private async Task<List<CourseStudentDto>> GetCourseStudentListAsync(Guid courseId)
        {
            var queryable = from student in _courseStudentRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on student.UserId equals user.ID
                            where student.CourseId == courseId && student.IsEnable
                            select new CourseStudentDto
                            {
                                ID = student.ID,
                                CreateTime = student.CreateTime,
                                StartTime = student.StartTime,
                                EndTime = student.EndTime,
                                TimesCount = student.TimesCount,
                                CourseId = student.CourseId,
                                UseCount = student.UseCount,
                                UserId = student.UserId,
                                CourseType = student.CourseType,
                                HeadUrl = user.U_Headportrait,
                                Name = user.U_NickName,
                                Code = user.U_Code,
                                PhoneNo = user.U_PhoneNum,
                            };
            return await queryable.ToListAsync();
        }

        /// <summary>
        /// 获取课程明细列表
        /// </summary>
        private async Task<IList<CourseDetailDto>> GetCourseDetailListAsync(Guid courseId)
        {
            var queryable = from detail in _courseDetailRepository.AsNoTracking()
                            where detail.CourseId == courseId
                            select new CourseDetailDto
                            {
                                ID = detail.ID,
                                CreateTime = detail.CreateTime,
                                StartTime = detail.StartTime,
                                EndTime = detail.EndTime,
                                TimesCount = detail.TimesCount,
                                CourseType = detail.CourseType,
                                Price = detail.Price,
                                ValidMonth = detail.ValidMonth,
                            };
            return await queryable.ToListAsync();
        }

        /// <summary>
        /// 获取课程计划列表
        /// </summary>
        private async Task<List<CoursePlanDto>> GetCoursePlanListAsync(Guid courseId)
        {
            var queryable = from plan in _coursePlanRepository.AsNoTracking()
                            where plan.CourseId == courseId
                            select new CoursePlanDto
                            {
                                ID = plan.ID,
                                CreateTime = plan.CreateTime,
                                StartTime = plan.StartTime,
                                EndTime = plan.EndTime,
                                CourseType = plan.CourseType,
                                WeekDay = plan.WeekDay,
                            };
            return await queryable.ToListAsync();
        }

        /// <summary>
        /// 购买验证
        /// </summary>
        private async Task<UnaryResult<CourseBuyResultDto>> BuyValidAsync(Course course, CourseBuyRequestDto request, CourseBuyResultDto result)
        {
            if (course == null)
            {
                return UnaryResult.From(10, result, "课程已不在");
            }

            if (course.State == CourseStateEnum.Stoped)
            {
                return UnaryResult.From(10, result, "课程已停止销售");
            }

            if (course.CourseType == CourseTypeEnum.Duration && !request.StartTime.HasValue)
            {
                return UnaryResult.From(10, result, "期间课程，开始日期必选");
            }

            request.StartTime ??= DateTimeOffset.Now.Date;
            if (course.CourseType == CourseTypeEnum.Duration && (request.StartTime > DateTimeOffset.Now.Date.AddDays(7) || request.StartTime < DateTimeOffset.Now.Date))
            {
                return UnaryResult.From(10, result, "日期范围未来7天内");
            }

            if (course.CourseType != CourseTypeEnum.Times)
            {
                var stateList = new List<CourseOrderStateEnum> { CourseOrderStateEnum.Paid, CourseOrderStateEnum.PartialRefunded };
                if (await _courseOrderRepository.AnyAsync(m => m.BusinessId == course.ID && m.UserId == _currentInfo.UserId
                && m.EndTime >= request.StartTime.Value.DateTime && stateList.Contains(m.State)))
                {
                    return UnaryResult.From(10, result, $"重复购买");
                }
            }
            else
            {
                var student = await _courseStudentRepository.AsNoTracking().FirstOrDefaultAsync(m => m.CourseId == course.ID && m.UserId == _currentInfo.UserId);
                if (student != null && student.TimesCount > 0)
                {
                    return UnaryResult.From(10, result, "次数课程重复购买");
                }
            }

            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 课程业务订单
        /// </summary>
        private async Task<CourseOrder> CreateOrderAsync(Course course, CourseDetail detail, CourseBuyRequestDto request, CourseBuyResultDto result)
        {
            var user = await _baseUserRepository.FirstOrDefaultAsync(m => m.ID == _currentInfo.UserId);
            var order = new CourseOrder
            {
                ID = Guid.NewGuid(),
                Name = course.Name,
                BusinessId = course.ID,
                BusinessType = BusinessTypeEnum.Course,
                OrderNo = Tool.BuildPayOrderNo(BusinessTypeEnum.Course),
                Address = string.IsNullOrWhiteSpace(course.VenueName) ? course.Address : course.VenueName,
                PayType = PayTypeEnum.None,
                State = CourseOrderStateEnum.NotPay,
                Price = detail.Price,
                OrderAmount = detail.Price,
                PayAmount = detail.Price,
                CourseType = course.CourseType,
                ValidMonth = detail.ValidMonth,
                TimesCount = detail.TimesCount,
                StartTime = request.StartTime.Value,
                Bonus = 0,
                BonusAmount = 0,
                CouponId = null,
                CouponAmount = 0,
                Remark = $"{course.Name}购买:{user.U_NickName ?? user.U_RealName}",
                RefundAmount = 0,
                RefundRemark = null,
                UserId = user.ID,
                Mobile = user.U_PhoneNum,
                UserName = user.U_NickName ?? user.U_RealName,
                IsNotRefund = false
            };

            switch (course.CourseType)
            {
                case CourseTypeEnum.None:
                case CourseTypeEnum.Times:
                    order.EndTime = order.StartTime.AddMonths(detail.ValidMonth);
                    break;
                case CourseTypeEnum.Duration:
                    order.EndTime = order.StartTime.AddMonths(detail.ValidMonth);
                    break;
                case CourseTypeEnum.Activity:
                    order.StartTime = detail.StartTime.Value;
                    order.EndTime = detail.EndTime.Value;
                    break;
            }

            result.CourseOrderId = order.ID;
            result.CourseOrderNo = order.OrderNo;
            result.CourseId = course.ID;
            return order;
        }

        #endregion
    }
}
